

import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import org.junit.Test;

/**
  todo 一、 方法应用:若Lambda体中的内容有方法已经实现了，我们可以使用"方法引用"
 * (可以理解为方法引用时Lambda表达式的另一种表现形式)
 * 
 * 主要有三种语法格式：
 * 对象：：实例方法名
 *  类：：静态方法名
*  类 ：：实例方法名
*
*注意:
*todo 1、Lambda体中调用方法的参数列表与返回值类型，要与函数接口中 抽象方法的参数列表和返回值保持一致！
 * todo 2.若Lambda参数列表中的第一个参数是实例方法的调用者，而第二个参数是实例方法的参数时，可以使用类名：：方法名，如test4()
 *
 * todo 二、构造器引用
  ClassName::new
 注意：需要调用构造器的单数列表要与函数式接口抽象方法的参数列表保持一致

todo  三、数组引用
Type::new
 *
 */
public class TestMethodRef {
  @Test//第一种方式对象：：实例方法名
  public void test1() {
	 PrintStream ps= System.out;
	  Consumer<String>con=(x)->ps.println(x);
	  con.accept("con");
	  
	  //todo 等级于下面的写法,这样参数可以省略了
	  PrintStream ps1 =System.out;
	  Consumer<String>con1=ps1::println;
	  con1.accept("con1");
	  
	  Consumer<String>con2=System.out::println;
	  con2.accept("con2");
	  
	  /**
	   *  todo 这样替换的前提是Consumer类的void accept(T t)/函数中抽象方法;和Lambda体
	   * PrintStream.println方法，void println(String x)，入参和返回值，都是一个参数返回值
	   *    都是void，这样参数不用显示传入了
	   * 
	   */
  }
  @Test
  //实例方法名
  public void test2() {
	  Employee emp=new Employee();
	  Supplier<Integer>sup=()->emp.getAge();
	  Integer str=sup.get();
	  System.out.println(str);
	  //等价于
	  Supplier<Integer>sup2=emp::getAge;
	  Integer num=sup2.get();
	  System.out.print(num);
	  
	  //todo getAge和Supplier 方法都是没有参数，且具有返回值
	  
  }
  
  //类::静态方法名
  @Test
  public void test3() {
	  Comparator<Integer>com=(x,y)->Integer.compare(x, y);
	  System.out.println(com.compare(1, 2));
	  
	  //等价于;Integer::compare和Comparator.compare 参数列表和返回值一致
	  Comparator<Integer>com1=Integer::compare;
	  System.out.println(com1.compare(1, 2));
	
  }
  
  //类：：实例方法名
  public void test4() {
	  
	  BiPredicate<String,String>bp=(x,y)->x.equals(y);
	  //可以等价于
	  BiPredicate<String,String>bp2=String::equals;

	  //todo 使用场景：第一个参数是方法的调用者(x,y)->x,第一个单数x是equals方法的调用者，第二个单数是方法的参数时就可以使用类名::实例方法名
  }

  //构造器引用
  @Test
  public void test5(){
  	//无参构造
  	Supplier<Employee>sup=()->new Employee();
  	System.out.println(sup.get().getAge());
  	//构造器引用方式
	Supplier<Employee>sup2=Employee::new;//todo 自动匹配对应的参数列表,因Supplier get是无参的 所以匹配无参构造
	System.out.println(sup2.get().getAge());

    //一个参数
	Function<Integer,Employee>fun=(x)->new Employee();//传入Integer参数；返回Employee对象
	Employee emp=fun.apply(101);
	System.out.println(emp);
	//等价于
	Function<Integer,Employee>fun1=Employee::new;//todo 自动匹配一个Integer类型参数构造，因为Function.apply是一个参数
	Employee emp2=fun1.apply(101);
	System.out.println(emp2);

	//两个参数可以使用BiFunction
  }
  //数组引用
  @Test
  public  void test7(){
   Function<Integer,String[]>fun=(x)->new String[x];
   String []strs=fun.apply(10);
   System.out.println(strs.length);

   Function<Integer,String[]>fun2=String[]::new;//根据Funciton.apply返回参数类型String推断出数据类型
   String[]str2=fun2.apply(10);
   System.out.println(str2.length);
  }
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
}
